﻿// ------------------------------------------------------------------------------
// <copyright file="XamlUserType.cs" company="skumaronline.com">
//    Copyright (C) 2012 Suresh Kumar T.  All rights reserved.
// </copyright>
// ------------------------------------------------------------------------------

namespace StoreAppLib.MetaData
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;
    using Windows.UI.Xaml.Markup;

    /// <summary>
    /// Custom XAML type
    /// </summary>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks", "4.0.0.0")]
    [System.Diagnostics.DebuggerNonUserCodeAttribute]
    public sealed class XamlUserType : XamlSystemBaseType
    {
        /// <summary>
        /// XAML type information provider
        /// </summary>
        private XamlTypeInfoProvider provider;

        /// <summary>
        /// The immediate base type of the XAML type
        /// </summary>
        private IXamlType baseType;

        /// <summary>
        /// Indicates whether the XAML type represents an array
        /// </summary>
        private bool isArray;

        /// <summary>
        /// Indicates whether the XAML type represents a mark-up extension
        /// </summary>
        private bool isMarkupExtension;

        /// <summary>
        /// Indicates whether the type support binding
        /// </summary>
        private bool isBindable;

        /// <summary>
        /// XAML member information for the XAML content property of this XAML type
        /// </summary>
        private string contentPropertyName;

        /// <summary>
        /// Item type name
        /// </summary>
        private string itemTypeName;

        /// <summary>
        /// The type information for the Key property of this
        /// XAML type, if this XAML type represents a dictionary/map
        /// </summary>
        private string keyTypeName;

        /// <summary>
        /// Member names
        /// </summary>
        private Dictionary<string, string> memberNames;

        /// <summary>
        /// Enumeration values
        /// </summary>
        private Dictionary<string, object> enumValues;

        /// <summary>
        /// Initializes a new instance of the <see cref="XamlUserType"/> class"
        /// </summary>
        /// <param name="provider">The XAML type information provider</param>
        /// <param name="fullName">Type full name</param>
        /// <param name="fullType">Backing type</param>
        /// <param name="baseType">Base XAML type</param>
        public XamlUserType(XamlTypeInfoProvider provider, string fullName, Type fullType, IXamlType baseType)
            : base(fullName, fullType)
        {
            this.provider = provider;
            this.baseType = baseType;
        }

        /// <summary>
        /// Gets the XAML type for the immediate base type of the XAML type
        /// </summary>
        public override IXamlType BaseType
        {
            get
            {
                return this.baseType;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the XAML type represents an array
        /// </summary>
        public override bool IsArray
        {
            get
            {
                return this.isArray;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this XAML type represents a collection
        /// </summary>
        public override bool IsCollection
        {
            get
            {
                return this.CollectionAdd != null;
            }
        }

        /// <summary>
        ///  Gets a value indicating whether this XAML type represents a constructible type, as per the XAML definition
        /// </summary>
        public override bool IsConstructible
        {
            get
            {
                return Activator != null;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this XAML type represents a dictionary/map
        /// </summary>
        public override bool IsDictionary
        {
            get
            {
                return this.DictionaryAdd != null;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the XAML type represents a mark-up extension
        /// </summary>
        public override bool IsMarkupExtension
        {
            get
            {
                return this.isMarkupExtension;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the type support binding
        /// </summary>
        public override bool IsBindable
        {
            get
            {
                return this.isBindable;
            }
        }

        /// <summary>
        /// Gets the XAML member information for the XAML content property of this XAML type
        /// </summary>
        public override IXamlMember ContentProperty
        {
            get
            {
                return this.provider.GetMemberByLongName(this.contentPropertyName);
            }
        }

        /// <summary>
        /// Gets a value that provides the type information for the Items property of this XAML type
        /// </summary>
        public override IXamlType ItemType
        {
            get
            {
                return this.provider.GetXamlTypeByName(this.itemTypeName);
            }
        }

        /// <summary>
        /// Gets a value that provides the type information for the Key property of this
        /// XAML type, if this XAML type represents a dictionary/map
        /// </summary>
        public override IXamlType KeyType
        {
            get
            {
                return this.provider.GetXamlTypeByName(this.keyTypeName);
            }
        }

        /// <summary>
        /// Gets or sets activator delegate
        /// </summary>
        public Activator Activator { get; set; }

        /// <summary>
        /// Gets or sets collection delegate
        /// </summary>
        public AddToCollection CollectionAdd { get; set; }

        /// <summary>
        /// Gets or sets dictionary delegate
        /// </summary>
        public AddToDictionary DictionaryAdd { get; set; }

        /// <summary>
        /// Returns the XAML member information for a specific named member from this XAML type
        /// </summary>
        /// <param name="name">The name of the member to get (as a string)</param>
        /// <returns>The XAML member information for the member</returns>
        public override IXamlMember GetMember(string name)
        {
            if (this.memberNames == null)
            {
                return null;
            }

            string longName;
            
            if (this.memberNames.TryGetValue(name, out longName))
            {
                return this.provider.GetMemberByLongName(longName);
            }
            
            return null;
        }

        /// <summary>
        /// Given a XAML type, sets its values for initialization and returns a usable instance
        /// </summary>
        /// <returns>The usable instance</returns>
        public override object ActivateInstance()
        {
            return Activator();
        }

        /// <summary>
        /// Adds an item to a custom map type
        /// </summary>
        /// <param name="instance">The type instance to set the map item to</param>
        /// <param name="key">The key of the map item to add</param>
        /// <param name="item">The value of the map item to add</param>
        public override void AddToMap(object instance, object key, object item)
        {
            this.DictionaryAdd(instance, key, item);
        }

        /// <summary>
        /// Adds an item to a custom vector type
        /// </summary>
        /// <param name="instance">The type instance to set the item to</param>
        /// <param name="item">The value of the item to add</param>
        public override void AddToVector(object instance, object item)
        {
            this.CollectionAdd(instance, item);
        }

        /// <summary>
        /// Invokes any necessary pre-activation logic as required by the XAML schema context and its platform dependencies
        /// </summary>
        public override void RunInitializer()
        {
            RuntimeHelpers.RunClassConstructor(UnderlyingType.TypeHandle);
        }

        /// <summary>
        /// Creates a type system representation based on a string. The main scenario for this usage is creating an 
        /// enumeration value and mapping the appropriate enumeration
        /// </summary>
        /// <param name="input">The string to create from</param>
        /// <returns>The resulting type system representation</returns>
        public override object CreateFromString(global::System.String input)
        {
            if (this.enumValues != null)
            {
                int value = 0;

                string[] valueParts = input.Split(',');

                foreach (string valuePart in valueParts)
                {
                    object partValue;
                    int enumFieldValue = 0;

                    try
                    {
                        if (this.enumValues.TryGetValue(valuePart.Trim(), out partValue))
                        {
                            enumFieldValue = Convert.ToInt32(partValue);
                        }
                        else
                        {
                            try
                            {
                                enumFieldValue = Convert.ToInt32(valuePart.Trim());
                            }
                            catch (FormatException)
                            {
                                foreach (string key in this.enumValues.Keys)
                                {
                                    if (string.Compare(valuePart.Trim(), key, StringComparison.OrdinalIgnoreCase) == 0)
                                    {
                                        if (this.enumValues.TryGetValue(key.Trim(), out partValue))
                                        {
                                            enumFieldValue = Convert.ToInt32(partValue);
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                        value |= enumFieldValue;
                    }
                    catch (FormatException)
                    {
                        throw new ArgumentException(input, FullName);
                    }
                }

                return value;
            }

            throw new ArgumentException(input, FullName);
        }

        /// <summary>
        /// Sets content property name
        /// </summary>
        /// <param name="contentPropertyName">Content property name</param>
        public void SetContentPropertyName(string contentPropertyName)
        {
            this.contentPropertyName = contentPropertyName;
        }

        /// <summary>
        /// Sets XAML type as array
        /// </summary>
        public void SetIsArray()
        {
            this.isArray = true;
        }

        /// <summary>
        /// Sets XAML type as mark up extension
        /// </summary>
        public void SetIsMarkupExtension()
        {
            this.isMarkupExtension = true;
        }

        /// <summary>
        /// Sets XAML type as supporting binding
        /// </summary>
        public void SetIsBindable()
        {
            this.isBindable = true;
        }

        /// <summary>
        /// Sets item type name
        /// </summary>
        /// <param name="itemTypeName">Item type name</param>
        public void SetItemTypeName(string itemTypeName)
        {
            this.itemTypeName = itemTypeName;
        }

        /// <summary>
        /// Sets key type name
        /// </summary>
        /// <param name="keyTypeName">Key type name</param>
        public void SetKeyTypeName(string keyTypeName)
        {
            this.keyTypeName = keyTypeName;
        }

        /// <summary>
        /// Add member name
        /// </summary>
        /// <param name="shortName">Member short name</param>
        public void AddMemberName(string shortName)
        {
            if (this.memberNames == null)
            {
                this.memberNames = new Dictionary<string, string>();
            }

            this.memberNames.Add(shortName, this.FullName + "." + shortName);
        }

        /// <summary>
        /// Add enumeration value
        /// </summary>
        /// <param name="name">The name</param>
        /// <param name="value">The value</param>
        public void AddEnumValue(string name, object value)
        {
            if (this.enumValues == null)
            {
                this.enumValues = new Dictionary<string, object>();
            }

            this.enumValues.Add(name, value);
        }
    }
}
